package com.thank.concurrency.samples.singleton;

import com.thank.concurrency.annoations.NotThreadSafe;

/**
 * 懒汉式 -> 双重同步锁单例模式
 *
 * 单例实例在第一次使用时进行创建
 *
 * 这里主要说明一下为什么这类是线程不安全的:
 * 同步代码instance = new SingletonExample4(); 是会包括三部分的:
 *     1. memory = allocate(); 分配对象的内存空间
 *     2. ctorInstance(); 初始化对象
 *     3. instance = memory; 设置instance指向刚分配的内存
 * 单线程下是没毛病的, 但在多线程情况下, 在JVM和CPU优化时, 可能会发生指令重排, 于是上面三步可能会变成:
 *     1. memory = allocate(); 分配对象的内存空间
 *     3. instance = memory; 设置instance指向刚分配的内存
 *     2. ctorInstance(); 初始化对象
 * 此时A线程和B线程都进去了, A处于3(instance = memory; 设置instance指向刚分配的内存), B处于判断实例是否为Null
 * 这是B的判断就不是null了, 直接执行return instance
 * 虽然这种几率很小, 或不造成什么影响, 但这也是线程不安全!
 */
@NotThreadSafe
public class SingletonExample4 {

    // 私有的构造方法
    private SingletonExample4() {}

    // 单例对象
    private static SingletonExample4 instance = null;

    // 静态的工厂方法
    public static SingletonExample4 getInstance() {
        // 双重检测机制
        if (null == instance) {  // Thread_B
            // 同步锁机制
            synchronized (SingletonExample4.class) {
                if (null == instance) {
                    instance = new SingletonExample4(); // Thread_A - 3
                }
            }

        }
        return instance;
    }

}
